package android.slc.box.core.launcher;

import android.slc.box.core.controller.EventPlusHandler;
import android.slc.box.core.virtual_android.Bundle;
import de.saxsys.mvvmfx.FxmlView;
import de.saxsys.mvvmfx.Scope;
import de.saxsys.mvvmfx.ViewModel;
import de.saxsys.mvvmfx.ViewTuple;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.stage.Window;

import java.util.Collection;
import java.util.List;

public interface WindowLauncher<T extends Window> {

    public static String ID_SCENE_ROOT_PANE = "sceneRootPane";

    /**
     * 是否是场景根节点
     *
     * @param scene
     * @return
     */
    static boolean isSceneRootPane(Scene scene) {
        return scene.getRoot() != null && WindowLauncher.ID_SCENE_ROOT_PANE.equals(scene.getRoot().getId());
    }

    /**
     * 获取场景根节点
     *
     * @param scene
     * @return
     */
    static Pane getSceneRootPane(Scene scene) {
        if (isSceneRootPane(scene)) {
            return (Pane) scene.getRoot();
        }
        return null;
    }

    /**
     * 获取主题
     *
     * @return
     */
    List<String> getStylesheets();

    /**
     * 获取Bundle
     *
     * @return
     */
    Bundle getBundle();

    /**
     * 获取窗口
     *
     * @return
     */
    T getWindow();

    /**
     * 获取窗口且不为空，为空则抛异常
     *
     * @return
     */
    default T requireWindow() {
        if (this.getWindow() == null) {
            throw new RuntimeException("当前启动的window对象为空，请检查是否传递window对象或该启动器为应用首个启动器");
        }
        return this.getWindow();
    }

    /**
     * 添加窗口关闭监听
     *
     * @param onWindowsCloseListener
     */
    void addOnWindowsCloseListener(EventPlusHandler.EventPlusHandlerListener onWindowsCloseListener);

    /**
     * 移除窗口关闭监听
     *
     * @param onWindowsCloseListener
     */
    void removeOnWindowsCloseListener(EventPlusHandler.EventPlusHandlerListener onWindowsCloseListener);

    /**
     * 切换场景
     *
     * @param scene 传递一个场景
     */
    void switchScene(Scene scene);

    /**
     * 切换视图
     *
     * @param rootView 传递一个跟布局
     */
    default void switchView(Parent rootView) {
        Pane sceneRootPaneRoot = getSceneRootPane(requireWindow().getScene());
        if (sceneRootPaneRoot != null) {
            sceneRootPaneRoot.getChildren().clear();
            sceneRootPaneRoot.getChildren().add(rootView);
        } else {
            requireWindow().getScene().setRoot(rootView);
        }
    }

    /**
     * 切换视图
     *
     * @param viewClass       布局的class
     * @param <ViewType>      布局泛型
     * @param <ViewModelType> viewModel类型
     */
    default <ViewType extends FxmlView<? extends ViewModelType>, ViewModelType extends ViewModel> void switchView(Class<ViewType> viewClass, Scope... scopes) {
        this.switchView(viewClass, null, scopes);
    }

    /**
     * 切换视图
     *
     * @param viewClass       布局的class
     * @param <ViewType>      布局泛型
     * @param <ViewModelType> viewModel类型
     */
    default <ViewType extends FxmlView<? extends ViewModelType>, ViewModelType extends ViewModel> void switchView(Class<ViewType> viewClass,
                                                                                                                  Bundle bundle, Scope... scopes) {
        switchView(createView(viewClass, bundle, scopes));
    }

    /**
     * 添加视图
     *
     * @param contentView 传递一个跟布局
     */
    default void addView(Parent contentView) {
        this.addView((Pane) requireWindow().getScene().getRoot(), contentView);
    }

    /**
     * 添加视图
     *
     * @param parentPane  parentPane
     * @param contentView 传递一个跟布局
     */
    void addView(Pane parentPane, Parent contentView);

    /**
     * 添加视图
     *
     * @param viewClass       布局的class
     * @param <ViewType>      布局泛型
     * @param <ViewModelType> viewModel类型
     */
    default <ViewType extends FxmlView<? extends ViewModelType>, ViewModelType extends ViewModel> void addView(Class<ViewType> viewClass, Scope... scopes) {
        this.addView(viewClass, null, scopes);
    }

    /**
     * 添加视图
     *
     * @param parentPane      parentPane
     * @param viewClass       布局的class
     * @param <ViewType>      布局泛型
     * @param <ViewModelType> viewModel类型
     */
    default <ViewType extends FxmlView<? extends ViewModelType>, ViewModelType extends ViewModel> void addView(Pane parentPane, Class<ViewType> viewClass, Scope... scopes) {
        this.addView(parentPane, viewClass, null, scopes);
    }

    /**
     * 添加视图
     *
     * @param viewClass       布局的class
     * @param <ViewType>      布局泛型
     * @param <ViewModelType> viewModel类型
     */
    default <ViewType extends FxmlView<? extends ViewModelType>, ViewModelType extends ViewModel> void addView(Class<ViewType> viewClass,
                                                                                                               Bundle bundle, Scope... scopes) {
        this.addView((Pane) requireWindow().getScene().getRoot(), viewClass, bundle, scopes);
    }

    /**
     * 添加视图
     *
     * @param parentPane      parentPane
     * @param viewClass       布局的class
     * @param <ViewType>      布局泛型
     * @param <ViewModelType> viewModel类型
     */
    default <ViewType extends FxmlView<? extends ViewModelType>, ViewModelType extends ViewModel> void addView(Pane parentPane, Class<ViewType> viewClass,
                                                                                                               Bundle bundle, Scope... scopes) {
        Parent view = createView(viewClass, bundle, scopes);
        addView(parentPane, view);
    }

    /**
     * 启动窗口
     *
     * @param targetWindow
     * @param parent
     */
    default void launcherWindow(T targetWindow, Parent parent) {
        StackPane rootPane = new StackPane(parent);
        rootPane.setId(ID_SCENE_ROOT_PANE);
        this.launcherWindow(targetWindow, new Scene(rootPane));
    }

    /**
     * 启动窗口
     *
     * @param targetWindow
     * @param scene
     */
    void launcherWindow(T targetWindow, Scene scene);


    /**
     * 启动窗口
     *
     * @param targetWindow
     * @param viewClass
     * @param scopes
     * @param <ViewType>
     * @param <ViewModelType>
     */
    default <ViewType extends FxmlView<? extends ViewModelType>, ViewModelType extends ViewModel> void launcherWindow(T targetWindow,
                                                                                                                      Class<ViewType> viewClass,
                                                                                                                      Scope... scopes) {
        this.launcherWindow(targetWindow, viewClass, null, scopes);
    }

    /**
     * 启动窗口
     *
     * @param targetWindow
     * @param viewClass
     * @param bundle
     * @param scopes
     * @param <ViewType>
     * @param <ViewModelType>
     */
    default <ViewType extends FxmlView<? extends ViewModelType>, ViewModelType extends ViewModel> void launcherWindow(T targetWindow,
                                                                                                                      Class<ViewType> viewClass,
                                                                                                                      Bundle bundle,
                                                                                                                      Scope... scopes) {
        launcherWindow(targetWindow, createView(viewClass, bundle, scopes));
    }

    /**
     * 创建视图
     *
     * @param viewClass       布局的class
     * @param <ViewType>      布局泛型
     * @param <ViewModelType> viewModel类型
     */
    default <ViewType extends FxmlView<? extends ViewModelType>, ViewModelType extends ViewModel> Parent createView(Class<ViewType> viewClass, Scope... scopes) {
        return createView(viewClass, null, scopes);
    }

    /**
     * 创建视图
     *
     * @param viewClass       布局的class
     * @param <ViewType>      布局泛型
     * @param <ViewModelType> viewModel类型
     */
    <ViewType extends FxmlView<? extends ViewModelType>, ViewModelType extends ViewModel> Parent createView(Class<ViewType> viewClass,
                                                                                                            Bundle bundle, Scope... scopes);

    /**
     * 创建ViewType
     *
     * @param viewClass
     * @param scopes
     * @param <ViewType>
     * @param <ViewModelType>
     * @return
     */
    <ViewType extends FxmlView<? extends ViewModelType>, ViewModelType extends ViewModel> ViewTuple<ViewType, ViewModelType> createViewTuple(Class<ViewType> viewClass,
                                                                                                                                             Collection<Scope> scopes);

    /**
     * 销毁
     */
    default void destroyLauncher() {
    }
}
